#include "ili9806e_mipi.h"

#if USE_LCD_PANEL_ILI9806E_MIPI

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "lvgl/src/lv_core/lv_refr.h"
#include "lvgl/src/lv_core/lv_disp.h"
#include "lvgl/src/lv_hal/lv_hal_tick.h"
#include "crane_lcdc.h"
#include "crane_lcd_mipi.h"
#include "crane_lcd_mipi_dsi.h"
#include "../common/utils.h"
#include "../common/lv_pm.h"
#include "../../board.h"
#include "lv_conf.h"

#define UNLOCK_DELAY         0
#define LCD_COLOR_DEPTH_BYTE (LV_COLOR_DEPTH / 8)
#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))

static lv_disp_drv_t * lcd_disp_drv = NULL;
static lcd_context g_lcd_ctx;

#define ID_TABLE_END 0
unsigned ili9806e_mipi_id_table[] = {
    0x04,
    ID_TABLE_END,
};

static struct s_dsi_cmd_desc ili9806e_init_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY, 2,{0xF0, 0xC3}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,6,{0xFF,0xFF,0x98,0x06,0x04,0x01}},  // Change to Page 1
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x08,0x10}},   // output SDA
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x21,0x01}},   // DE = 1 Active
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x30,0x00}},   // 480 X 864
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x31,0x02}},   // 2dot Inversion
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x40,0x14}},   // AVDD=2.5 VCI,0xAVEE=-3VCI
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x41,0x22}},   // AVDD=5 AVEE=-5 clamp
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x42,0x01}},   // VGH/VGL setting  -12.8v
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x43,0x85}},   // VGH Clamp 13V
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x44,0x89}},   // VGLClamp   0B
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x45,0x1B}},   // VGH_REG ,0xVGL_REG
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x50,0x68}},   // VREG1=4.3
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x51,0x68}},   // VREG2=-4.3
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x52,0x00}},   // Flicker when GS=0
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x53,0x55}},   // Flicker when GS=0 -1.2
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x57,0x50}},   // LVD
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x60,0x07}},   // SDTI
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x61,0x00}},   // CRTI
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x62,0x07}},   // EQTI
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x63,0x00}},   // PCTI

    //++++++++++++++++++ Gamma Setting 2++++++++++++++++++//
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA0,0x00}},  // Gamma 0
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA1,0x07}},  // Gamma 4
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA2,0x0D}},  // Gamma 8
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA3,0x0B}},  // Gamma 16
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA4,0x02}},  // Gamma 32
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA5,0x08}},  // Gamma 52
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA6,0x07}},  // Gamma 80
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA7,0x05}},  // Gamma 108
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA8,0x07}},  // Gamma 147
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xA9,0x0B}},  // Gamma 175
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xAA,0x11}},  // Gamma 203 14 236
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xAB,0x0A}},  // Gamma 223
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xAC,0x0E}},  // Gamma 239
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xAD,0x1A}},  // Gamma 247 1D
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xAE,0x12}},  // Gamma 251
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xAF,0x00}},  // Gamma 255
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC0,0x00}},  // Gamma 0
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC1,0x07}},  // Gamma 4
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC2,0x0D}},  // Gamma 8
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC3,0x0B}},  // Gamma 16
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC4,0x02}},  // Gamma 32
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC5,0x08}},  // Gamma 52
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC6,0x07}},  // Gamma 80
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC7,0x05}},  // Gamma 108
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC8,0x07}},  // Gamma 147
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xC9,0x0B}},  // Gamma 175
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xCA,0x11}},  // Gamma 203
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xCB,0x0A}},  // Gamma 223
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xCC,0x0E}},  // Gamma 239 18
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xCD,0x1A}},  // Gamma 247
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xCE,0x12}},  // Gamma 251
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xCF,0x00}},  // Gamma 255
    //**************************************************************************//
    //****************************** Page 6 Command ****************************//
    //**************************************************************************//
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,6,{0xFF,0xFF,0x98,0x06,0x04,0x06}},  // Change to Page 6
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x00,0x20}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x01,0x05}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x02,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x03,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x04,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x05,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x06,0x88}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x07,0x04}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x08,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x09,0x90}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x0A,0x04}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x0B,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x0C,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x0D,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x0E,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x0F,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x10,0x55}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x11,0x50}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x12,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x13,0x0C}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x14,0x0D}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x15,0x43}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x16,0x0B}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x17,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x18,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x19,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x1A,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x1B,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x1C,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x1D,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x20,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x21,0x23}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x22,0x45}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x23,0x67}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x24,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x25,0x23}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x26,0x45}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x27,0x67}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x30,0x02}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x31,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x32,0x11}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x33,0xAA}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x34,0xBB}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x35,0x66}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x36,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x37,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x38,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x39,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3A,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3B,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3C,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3D,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3E,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3F,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x40,0x22}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x52,0x10}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x53,0x10}},  // 0x10:VGLO tie VGL; 0x12:VGLO tie VGL_REG
    //**************************************************************************//
    //****************************** Page 7 Command ****************************//
    //**************************************************************************//
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,6,{0xFF,0xFF,0x98,0x06,0x04,0x07}},  // Change to Page 7
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x17,0x22}},  // 0x22:VGLO tie VGL; 0x32:VGLO tie VGL_REG
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x18,0x1D}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xE1,0x79}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x02,0x77}},
    //**************************************************************************//
    //****************************** Page 0 Command ****************************//
    //**************************************************************************//
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,6,{0xFF,0xFF,0x98,0x06,0x04,0x00}},   // Change to Page 0
    {DSI_DCS_SWRITE,DSI_LP_MODE,UNLOCK_DELAY,1,{0x35}},
    {DSI_DCS_SWRITE,DSI_LP_MODE,120,1,{0x11}},
    {DSI_DCS_SWRITE,DSI_LP_MODE,10,1,{0x29}},
};

static struct s_dsi_cmd_desc ili9806e_set_cmds[] = {
    {DSI_DCS_LWRITE, DSI_LP_MODE, 1, 6, {0xFF, 0xFF, 0x98, 0x06,0x04,0x01}},
    {DSI_SET_MAX_PKT_SIZE, DSI_LP_MODE, UNLOCK_DELAY, 1, {0x1}},
};

static struct s_dsi_cmd_desc ili9806e_read_id_cmds[] = {
    {DSI_GENERIC_READ1, DSI_LP_MODE, UNLOCK_DELAY, 1, {0x2}},
};

static struct s_dsi_cmd_desc ili9806e_display_on_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,6,{0xFF,0xFF,0x98,0x06,0x04,0x00}},   // Change to Page 0
    {DSI_DCS_SWRITE,DSI_LP_MODE,UNLOCK_DELAY,1,{0x35}},
    {DSI_DCS_SWRITE,DSI_LP_MODE,120,1,{0x11}},
    {DSI_DCS_SWRITE,DSI_LP_MODE,20,1,{0x29}},
};

static struct s_dsi_cmd_desc ili9806e_display_off_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,6,{0xFF,0xFF,0x98,0x06,0x04,0x00}},   // Change to Page 0
    {DSI_DCS_SWRITE,DSI_LP_MODE,UNLOCK_DELAY,1,{0x35}},
    {DSI_DCS_SWRITE,DSI_LP_MODE,20,1,{0x28}},
    {DSI_DCS_SWRITE,DSI_LP_MODE,120,1,{0x10}},
};

const static struct s_mipi_info lcd_ili9806e_mipi_info = {
    480, /*width*/
    864, /*height*/
    16,//132, /*hfp*/
    16,//156, /*hbp*/
    32,//12, /*hsync*/
    4,//24, /*vfp*/
    4,//36, /*vbp*/
    16,//4, /*vsync*/
    60, /*fps*/

    DSI_MODE_VIDEO, /*work_mode*/
    DSI_INPUT_DATA_RGB_MODE_565, /*rgb_mode*/
    1, /*lane_number*/
    490000, /*phy_freq: KHz*/ //should be
    0, /*split_enable*/
    1, /*eotp_enable*/

    DSI_BURST_MODE_BURST, /*burst_mode*/

    /*following force to 0*/
    0, /*te_enable*/
    0, /*vsync_pol*/
    0, /*te_pol*/
    0, /*te_mode*/

    /*The following fields need not be set by panel*/
    0,
};

static uint8_t suspend_flag = 0;
static void ili9806e_mipi_suspend(void *arg)
{
    struct crane_panel_t *p = arg;
    printf("ili9806e_mipi_suspend\n");

    /*since disp_refr can be changed by other register,
     *so if ili9806e suspend need use lcd_disp_drv instead of lv_refr_vdb_is_flushing()
     *refer to lv_disp_refr_task() and lv_refr_vdb_flush()*/
    if(lcd_disp_drv && lcd_disp_drv->buffer) {
        // wait flushing finish~~
        while(lcd_disp_drv->buffer->flushing)
            ;
    }

    lcdc_stop(&g_lcd_ctx);
    lcd_dsi_after_refresh();
    p->panel_onoff(0);
    lcd_mipi_uninit();
    suspend_flag = 1;
}

static void ili9806e_mipi_resume(void *arg)
{
    struct crane_panel_t *p = arg;
    printf("ili9806e_mipi_resume\n");
    lcdc_resume();
    p->panel_onoff(1);
    lcd_dsi_before_refresh();

    suspend_flag = 0;
    lv_obj_invalidate(lv_disp_get_scr_act(NULL));
    lv_refr_now(_lv_refr_get_disp_refreshing());

    if(lcd_disp_drv && lcd_disp_drv->buffer) {
        // wait flushing finish~~
        while(lcd_disp_drv->buffer->flushing)
            ;
    }
}

static void ili9806e_mipi_panel_invalid(uint32_t start_x,
                                  uint32_t start_y,  uint32_t end_x, uint32_t end_y)
{

}

static int match_id(unsigned id, unsigned *id_table)
{
    int found = 0;
    unsigned *p = id_table;

    while (*p) {
        if (id == *p) {
            found = 1;
            break;
        }
        p++;
    }

    return (found == 1) ? 1 : 0;
}

static int ili9806e_mipi_read_id(unsigned *pid)
{
    struct s_dsi_rx_buf dbuf;
    int id[5];

    lcd_dsi_write_cmds(ili9806e_set_cmds, ARR_SIZE(ili9806e_set_cmds));

    lcd_dsi_read_cmds(&dbuf, ili9806e_read_id_cmds,ARR_SIZE(ili9806e_read_id_cmds));
    id[0] = dbuf.data[0];
    id[1] = dbuf.data[1];
    id[2] = dbuf.data[2];
    id[3] = dbuf.data[3];
    id[4] = dbuf.data[4];
    printf("ili9806e_mipi_read_id: data 0 - 4 is 0x%x, 0x%x, 0x%x, 0x%x, 0x%x \n",
         id[0],id[1],id[2],id[3],id[4]);

    *pid = id[0];
    return 0;
}

__attribute__ ((unused)) static int panel_detect_readid(void)
{
    unsigned id = 0;
    if (ili9806e_mipi_read_id(&id) < 0) {
        printf("panel read id failed\n");
        goto err;
    }

    if (match_id(id, ili9806e_mipi_id_table) == 0) {
        printf("unknown panel id = 0x%x\n", id);
        goto err;
    }

    printf("Found LCD panel ili9806e-mipi, id: 0x%x\n", id);
    printf("panel detect by readid ok\n");

    return 0;
err:
    printf("panel detect by readid failed\n");
    return -1;
}

typedef int (*panel_detect_fn_t)(void);

static panel_detect_fn_t detect_fn[] = {
    panel_detect_readid,
};

static int panel_detect(void)
{
    int cnt = ARRAY_SIZE(detect_fn);
    int i, ret;

    for (i = 0; i < cnt; i++) {
        ret = detect_fn[i]();
        if (ret == 0) {
            return 0;
        }
    }

    return -1;
}

static void ili9806e_mipi_onoff(int on)
{
    if (on) {
      lcd_dsi_write_cmds(ili9806e_display_on_cmds, ARR_SIZE(ili9806e_display_on_cmds));
    } else {   /* off */
      lcd_dsi_write_cmds(ili9806e_display_off_cmds, ARR_SIZE(ili9806e_display_off_cmds));
    }
}

static int ili9806e_mipi_probe(unsigned lcd_clk)
{
    static int inited = 0;
    lv_pm_info_t pm_info;

    lcd_mipi_init(lcd_clk, 0, &lcd_ili9806e_mipi_info);
    lcd_mipi_reset();

    if(inited) {
        return 0;
    }

    int silent_reset = startup_silent_reset();
    if(!silent_reset) {
        lcdc_reset_panel();
    }

    if (panel_detect() < 0) {
        return -1;
    }

    lcd_dsi_write_cmds(ili9806e_init_cmds, ARR_SIZE(ili9806e_init_cmds));

    memset(&g_lcd_ctx, 0, sizeof(lcd_context));
    g_lcd_ctx.bg_color = 0x0000ff; /*bg color : red*/
    g_lcd_ctx.alpha_mode = LCD_ALPHA_MODE_NORMAL;
    g_lcd_ctx.output_config.format = MIPI_FORMAT_VIDEO;

    pm_info.suspend = ili9806e_mipi_suspend;
    pm_info.resume = ili9806e_mipi_resume;
    pm_info.data = &ili9806e_mipi;
    pm_info.part = LV_PM_PART_DISPLAY;
    lv_pm_register(&pm_info);
    inited = 1;

    lcd_dsi_before_refresh();
    return 0;
}

/*refer to lv_port_disp_template.c, when lcdc_irq come, set lv_disp_flush_ready()*/
static void ili9806e_mipi_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    //printf("ili9806e_mipi_flush: [%d, %d] , [%d, %d]\n", area->x1, area->y1, area->x2, area->y2);
    lcd_disp_drv = disp_drv;
    if(suspend_flag == 1) {
        lv_disp_flush_ready(disp_drv);
        return;
    }

    uint32_t width, height, stride;
    unsigned buf_len;

    width = area->x2 - area->x1 + 1;
    height = area->y2 - area->y1 + 1;
#if (LV_COLOR_DEPTH == 16)
    stride = width * LCD_COLOR_DEPTH_BYTE;
#else
    printf("lv config is not 16 bits color depth !!!!!!!!!!!\n");
    return;
#endif
    buf_len = stride * height;

    flush_cache((unsigned long)color_p, buf_len);
    g_lcd_ctx.layer_config_osd1.buf1 = (void *)color_p;
    g_lcd_ctx.layer_config_osd1.format = LCD_FORMAT_RGB565;
    g_lcd_ctx.layer_config_osd1.layer_enable = 1;
    g_lcd_ctx.layer_config_osd1.stride = stride;
    g_lcd_ctx.layer_config_osd1.x = 0;
    g_lcd_ctx.layer_config_osd1.y = 0;
    g_lcd_ctx.layer_config_osd1.width = width;
    g_lcd_ctx.layer_config_osd1.height = height;
    g_lcd_ctx.layer_config_osd1.alpha = 0xff;

    g_lcd_ctx.wb_config.wb_enable = 0;
    g_lcd_ctx.layer_config_img.layer_enable = 0;

    lcdc_update_output_setting(&g_lcd_ctx.output_config, width, height);
    lcdc_update_mipi_output_setting(&g_lcd_ctx.output_config, &lcd_ili9806e_mipi_info);
    ili9806e_mipi_panel_invalid(area->x1, area->y1, area->x2, area->y2);

    lcdc_sync(&g_lcd_ctx, 1); /* irq mode */
    lv_disp_flush_ready(disp_drv);
}

struct crane_panel_t ili9806e_mipi = {
    .probe = ili9806e_mipi_probe, /* lcd_init() in board_evb.c also need change */
    .readid = ili9806e_mipi_read_id,
    .panel_onoff = ili9806e_mipi_onoff,
    .flush = ili9806e_mipi_flush,
};

#endif
